package com.hcms.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.hcms.admin.dto.SysAdminInfoResponse;
import com.hcms.admin.service.*;
import com.hcms.common.exception.ApiException;
import com.hcms.common.util.JwtTokenUtil;
import com.hcms.mybatis.entity.SysAdmin;
import com.hcms.mybatis.entity.SysAdminRole;
import com.hcms.mybatis.entity.SysRole;
import com.hcms.mybatis.mapper.SysAdminMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 后台用户表 服务实现类
 * </p>
 *
 * @author achenxw@126.com
 * @since 2023-02-13
 */
@Service
public class SysAdminServiceImpl extends ServiceImpl<SysAdminMapper, SysAdmin> implements ISysAdminService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //超级管理员权限标识
    private static final String ADMIN_ROLE_PERM = "ROLE_1";

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private SysAdminMapper sysAdminMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private ISysAdminRoleService sysAdminRoleRelationService;

    @Override
    public String refreshToken(String oldToken) {
        return jwtTokenUtil.refreshToken(oldToken);
    }


    @Override
    public SysAdminInfoResponse getInfo(String username) {
        //获取用户基本信息
        logger.info("Run getInfo(), username={}", username);
        SysAdmin sysAdmin = getAdminByUsername(username, true);
        //获取用户角色列表
        Collection<SysRole> sysRoles = sysAdminRoleRelationService.getRoles(sysAdmin.getId());
        if (sysRoles.size() < 1) {
            logger.error("Role acquisition failure");
            throw new ApiException("获取角色失败");
        }
        logger.info("Succeeded in obtaining the role");
        List<String> roleNames = sysRoles.stream().map(SysRole::getName).collect(Collectors.toList());
        //取用户权限
        Collection<String> permissionList = getPermissionsByAdminId(sysAdmin.getId(), true);
        //格式化返回数据
        return SysAdminInfoResponse.builder().username(username).nickName(sysAdmin.getNickName()).icon(sysAdmin.getIcon()).roles(roleNames).perms(permissionList).build();
    }

    @Override
    public SysAdmin register(SysAdmin sysAdmin) {
        logger.info("Registered user, username:" + sysAdmin.getUsername());
        SysAdmin insertAdmin = new SysAdmin();
        BeanUtil.copyProperties(sysAdmin, insertAdmin);
        insertAdmin.setCreateTime(new Date());
        insertAdmin.setStatus(SysAdmin.STATUS_ENABLE);
        //判断是否有相同的用户名
        logger.info("Check whether the username is available");
        LambdaQueryWrapper<SysAdmin> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysAdmin::getUsername, insertAdmin.getUsername());
        SysAdmin selectAdmin = sysAdminMapper.selectOne(queryWrapper);
        if (selectAdmin != null) {
            logger.error("The username already exists");
            throw new ApiException("用户名已存在");
        }
        logger.info("The username can be used");
        //对密码进行加密操作
        insertAdmin.setPassword(passwordEncoder.encode(insertAdmin.getPassword()));
        int insert = sysAdminMapper.insert(insertAdmin);
        if (insert > 0) {
            logger.info("Adding a new user succeeded");
            return insertAdmin;
        } else {
            logger.error("Failed to add a new user");
            return null;
        }
    }

    @Override
    public SysAdmin getView(Long id) {
        logger.info("Get detailed user data, id={}", id);
        return sysAdminMapper.selectById(id);
    }

    @Override
    public int createItem(SysAdmin entity) {
        logger.info("Run createItem(), username={}", entity.getUsername());
        if (StrUtil.isEmpty(entity.getUsername())) {
            throw new ApiException("账号不能为空");
        }
        if (StrUtil.isEmpty(entity.getNickName())) {
            throw new ApiException("昵称不能为空");
        }
        if (StrUtil.isEmpty(entity.getPassword())) {
            throw new ApiException("密码不能为空");
        }
        if (StrUtil.isEmpty(entity.getIcon())) {
            throw new ApiException("头像不能为空");
        }
        logger.info("Add a new user");
        entity.setId(0L);
        entity.setPassword(passwordEncoder.encode(SecureUtil.md5(entity.getPassword())));
        entity.setCreateTime(new Date());
        return sysAdminMapper.insert(entity);
    }

    @Override
    public int updateItem(Long id, SysAdmin entity) {
        logger.info("Run updateItem(), id={}", id);
        entity.setId(id);
        if (StrUtil.isEmpty(entity.getPassword())) {
            entity.setPassword(null);
        } else {
            entity.setPassword(passwordEncoder.encode(SecureUtil.md5(entity.getPassword())));
        }
        //删除缓存中数据
        if (StrUtil.isNotEmpty(entity.getUsername())) {
            getCacheService().delAdmin(entity.getUsername());
            getCacheService().delPermission(id);
        }
        logger.info("Update user information");
        return sysAdminMapper.updateById(entity);
    }

    @Override
    public List<SysAdmin> getList(String keyword, Integer status, Integer pageNum, Integer pageSize) {
        logger.info("Run getList(), keyword={}, status={}, pageNum={}, pageSize={}", keyword, status, pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize, "id DESC");
        LambdaQueryWrapper<SysAdmin> queryWrapper = new LambdaQueryWrapper<>();
        if (status != null) {
            queryWrapper.eq(SysAdmin::getStatus, status);
        }
        if (!StrUtil.isEmpty(keyword)) {
            queryWrapper.like(SysAdmin::getNickName, keyword).or().like(SysAdmin::getUsername, keyword);
        }
        logger.info("Obtaining record successfully");
        return sysAdminMapper.selectList(queryWrapper);
    }

    @Override
    public int deleteItem(String ids) {
        logger.info("Run deleteItem(), ids={}", ids);
        String[] split = ids.split(",");
        List<String> list = Arrays.asList(split);
        Collection<Long> collect = list.stream().map(Long::parseLong).collect(Collectors.toList());
        return sysAdminMapper.deleteBatchIds(collect);
    }

    @Override
    public SysAdmin getAdminByUsername(String username, Boolean mustFromDB) {
        logger.info("Run getAdminByUsername(), username={}", username);
        SysAdmin sysAdmin = getCacheService().getAdminByUsername(username);
        if (sysAdmin == null || mustFromDB) {
            LambdaQueryWrapper<SysAdmin> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SysAdmin::getUsername, username);
            sysAdmin = sysAdminMapper.selectOne(wrapper);
            logger.info("Select from database");
            if (sysAdmin != null) {
                logger.info("Save the data to the cache");
                getCacheService().setAdmin(sysAdmin);
            }
        }
        return sysAdmin;
    }

    @Override
    public Collection<String> getPermissionsByAdminId(Long adminId, Boolean mustFromDB) {
        logger.info("Run getPermissionByAdminId(), adminId={}", adminId);
        Collection<String> result = getCacheService().getPermissionAdminId(adminId);
        if (result == null || mustFromDB) {
            //获取用户角色
            logger.info("Get permission data from the database");
            result = new HashSet<>();
            Collection<SysRole> roles = getAdminRoles(adminId);
            List<String> rolePermission = roles.stream().map(role -> "ROLE_" + role.getId()).collect(Collectors.toList());
            Collection<String> permissions = sysAdminMapper.getPermissionsByAdminId(adminId);
            result.addAll(rolePermission);
            result.addAll(permissions);
            getCacheService().setPermission(adminId, result);
        } else {
            logger.info("Get data from the cache");
        }
        return result;
    }

    @Override
    public ISysAdminCacheService getCacheService() {
        return SpringUtil.getBean(ISysAdminCacheService.class);
    }

    @Override
    public boolean setAdminRoles(Long adminId, String roles) {
        logger.info("Run setRoles(), adminId={}, roles={}", adminId, roles);
        String[] split = StrUtil.isEmpty(roles) ? new String[0] : roles.split(",");
        Collection<Long> newRoles = Arrays.stream(split).map(Long::new).collect(Collectors.toList());
        //获取已有角色
        Collection<SysRole> roleByAdminId = sysAdminRoleRelationService.getRoles(adminId);
        Collection<Long> oldRoles = roleByAdminId.stream().map(SysRole::getId).collect(Collectors.toList());
        //添加角色
        Collection<Long> addRoles = new ArrayList<>(newRoles);
        addRoles.removeAll(oldRoles);
        List<SysAdminRole> entityList = addRoles.stream().map(id -> {
            SysAdminRole relation = new SysAdminRole();
            relation.setId(null);
            relation.setAdminId(adminId);
            relation.setRoleId(id);
            return relation;
        }).collect(Collectors.toList());
        if (entityList.size() > 0) {
            logger.info("Add a new role");
            sysAdminRoleRelationService.saveBatch(entityList);
        }
        //删除角色
        Collection<Long> delRoles = new ArrayList<>(oldRoles);
        delRoles.removeAll(newRoles);
        if (delRoles.size() > 0) {
            logger.info("Delete useless roles");
            LambdaQueryWrapper<SysAdminRole> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysAdminRole::getAdminId, adminId);
            queryWrapper.in(SysAdminRole::getRoleId, delRoles);
            sysAdminRoleRelationService.remove(queryWrapper);
        }
        logger.info("Set roles success");
        // 删除缓存中的数据
        getCacheService().delPermission(adminId);
        return true;
    }

    @Override
    public boolean checkPermissions(String[] perms) {
        logger.info("Run checkPermissions()");
        List<String> list = Arrays.asList(perms);
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            logger.error("Failed to obtain the permission list");
            return false;
        }
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        List<String> userPerms = authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
        //超级管理员拥有所有权限
        if (userPerms.contains(ADMIN_ROLE_PERM)) {
            logger.info("The user is super admin");
            return true;
        }
        //检查用户是否有权限
        return !Collections.disjoint(list, userPerms);
    }

    @Override
    public boolean changePassword(Long adminId, String password, String newPassword) {
        logger.info("Run changePassword(), adminId={}", adminId);
        if (StrUtil.isEmpty(password)) {
            throw new ApiException("旧密码不能为空");
        }
        if (StrUtil.isEmpty(newPassword)) {
            throw new ApiException("新密码不能为空");
        }
        if (password.equals(newPassword)) {
            throw new ApiException("新密码和旧密码不能一样");
        }
        SysAdmin admin = getView(adminId);
        if (!passwordEncoder.matches(password, admin.getPassword())) {
            throw new ApiException("旧密码错误");
        }
        admin.setPassword(passwordEncoder.encode(newPassword));
        int count = sysAdminMapper.updateById(admin);
        if (count > 0) {
            //删除缓存中数据
            getCacheService().delAdmin(admin.getUsername());
            getCacheService().delPermission(admin.getId());
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Collection<SysRole> getAdminRoles(Long adminId) {
        logger.info("Run getRoles(), adminId={}", adminId);
        return sysAdminRoleRelationService.getRoles(adminId);
    }

}
